home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 126-150 / disk_147 / sys / default / tty.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  11KB  |  443 lines

  1. /*
  2.  * Termcap/terminfo display driver
  3.  *
  4.  * Termcap is a terminal information database and routines to describe
  5.  * terminals on most UNIX systems.  Many other systems have adopted
  6.  * this as a reasonable way to allow for widly varying and ever changing
  7.  * varieties of terminal types.     This should be used where practical.
  8.  */
  9. /* Known problems:
  10.  *    If you have a terminal with no clear to end of screen and
  11.  *    memory of lines below the ones visible on the screen, display
  12.  *    will be wrong in some cases.  I doubt that any such terminal
  13.  *    was ever made, but I thought everyone with delete line would
  14.  *    have clear to end of screen too...
  15.  *
  16.  *    Code for terminals without clear to end of screen and/or clear
  17.  *    to end of line has not been extensivly tested.
  18.  *
  19.  *    Cost calculations are very rough.  Costs of insert/delete line
  20.  *    may be far from the truth.  This is accentuated by display.c
  21.  *    not knowing about multi-line insert/delete.
  22.  *
  23.  *    Using scrolling region vs insert/delete line should probably
  24.  *    be based on cost rather than the assuption that scrolling
  25.  *    region operations look better.
  26.  */
  27. #include    "def.h"
  28.  
  29. #define BEL    0x07            /* BEL character.        */
  30.  
  31. extern    int    ttrow;
  32. extern    int    ttcol;
  33. extern    int    tttop;
  34. extern    int    ttbot;
  35. extern    int    tthue;
  36.  
  37. int    tceeol;            /* Costs are set later */
  38. int    tcinsl;
  39. int    tcdell;
  40.  
  41. static    int    insdel;        /* Do we have both insert & delete line? */
  42.  
  43. #ifdef NO_RESIZE
  44. static    setttysize();
  45. #endif
  46.  
  47. char    *tgetstr();
  48. char    *tgoto();
  49. int    ttputc();
  50.  
  51. #define TCAPSLEN 1024
  52.  
  53. char tcapbuf[TCAPSLEN];
  54.  
  55. /* PC, UP, and BC are used by termlib, so must be extern and have these
  56.  * names unless you have a non-standard termlib.
  57.  */
  58.  
  59. int    LI;            /* standard # lines */
  60. char    PC,
  61.     *CM,
  62.     *CE,
  63.     *UP,
  64.     *BC,
  65.     *IM,            /* insert mode */
  66.     *IC,            /* insert a single space */
  67.     *EI,            /* end insert mode */
  68.     *DC,
  69.     *AL,            /* add line */
  70.     *DL,            /* del line */
  71.     *pAL,            /* parameterized add line */
  72.     *pDL,            /* parameterized delete line */
  73.     *TI,            /* term init -- start using cursor motion */
  74.     *TE,            /* term end --- end using cursor motion */
  75.     *SO,
  76.     *SE,
  77.     *CD,
  78.     *CS,            /* set scroll region            */
  79.     *SF,            /* forw index (used with scroll region)    */
  80.     *SR;            /* back index (used with scroll region)    */
  81. #ifdef    XKEYS
  82. char    *KS, *KE;        /* enter keypad mode, exit keypad mode    */
  83. #endif
  84. int    SG;    /* number of glitches, 0 for invisible, -1 for none    */
  85.     /* (yes virginia, there are terminals with invisible glitches)    */
  86.  
  87. /*
  88.  * Initialize the terminal when the editor
  89.  * gets started up.
  90.  */
  91. static char tcbuf[1024];
  92.  
  93. ttinit() {
  94.     char *tv_stype;
  95.     char *t, *p, *tgetstr();
  96. #ifndef gettermtype        /* (avoid declaration if #define) */
  97.     char *gettermtype();    /* system dependent function to determin terminal type */
  98. #endif
  99.  
  100.     if((tv_stype = gettermtype()) == NULL)
  101.         panic("Could not determine terminal type");
  102.     if((tgetent(tcbuf, tv_stype)) != 1) {
  103.         (VOID) strcpy(tcbuf, "Unknown terminal type ");
  104.         (VOID) strcat(tcbuf, tv_stype);
  105.         panic(tcbuf);
  106.     }
  107.  
  108.     p = tcapbuf;
  109.     t = tgetstr("pc", &p);
  110.     if(t) PC = *t;
  111.  
  112.     LI = tgetnum("li");
  113.     CD = tgetstr("cd", &p);
  114.     CM = tgetstr("cm", &p);
  115.     CE = tgetstr("ce", &p);
  116.     UP = tgetstr("up", &p);
  117.     BC = tgetstr("bc", &p);
  118.     IM = tgetstr("im", &p);
  119.     IC = tgetstr("ic", &p);
  120.     EI = tgetstr("ei", &p);
  121.     DC = tgetstr("dc", &p);
  122.     AL = tgetstr("al", &p);
  123.     DL = tgetstr("dl", &p);
  124.     pAL= tgetstr("AL", &p);    /* parameterized insert and del. line */
  125.     pDL= tgetstr("DL", &p);
  126.     TI = tgetstr("ti", &p);
  127.     TE = tgetstr("te", &p);
  128.     SO = tgetstr("so", &p);
  129.     SE = tgetstr("se", &p);
  130.     CS = tgetstr("cs", &p); /* set scrolling region */
  131.     SF = tgetstr("sf", &p);
  132.     if(!SF || !*SF) {    /* this is what GNU Emacs does */
  133.         SF = tgetstr("do", &p);
  134.         if(!SF || !*SF) {
  135.         SF = tgetstr("nl", &p);
  136.         if(!SF || !*SF) SF = "\n";
  137.         }
  138.     }
  139.     SR = tgetstr("sr", &p);
  140.     SG = tgetnum("sg");    /* standout glitch    */
  141. #ifdef    XKEYS
  142.     KS = tgetstr("ks", &p);    /* keypad start, keypad end    */
  143.     KE = tgetstr("ke", &p);
  144. #endif
  145.  
  146.     if(CM == NULL || UP == NULL)
  147.         panic("This terminal is to stupid to run MicroGnuEmacs\n");
  148.     ttresize();            /* set nrow & ncol    */
  149.  
  150.     /* watch out for empty capabilities (sure to be wrong)    */
  151.     if (CE && !*CE) CE = NULL;
  152.     if (CS && !*CS) CS = NULL;
  153.     if (SR && !*SR) SR = NULL;
  154.     if (AL && !*AL) AL = NULL;
  155.     if (DL && !*DL) DL = NULL;
  156.     if (pAL && !*pAL) pAL = NULL;
  157.     if (pDL && !*pDL) pDL = NULL;
  158.     if (CD && !*CD) CD = NULL;
  159.  
  160.     if(!CE) tceeol = ncol;
  161.     else    tceeol = charcost(CE);
  162.  
  163.     /* Estimate cost of inserting a line */
  164.     if (CS && SR)    tcinsl = charcost(CS)*2 + charcost(SR);
  165.     else if (pAL)    tcinsl = charcost(pAL);
  166.     else if (AL)    tcinsl = charcost(AL);
  167.     else        tcinsl = NROW * NCOL;    /* make this cost high enough */
  168.  
  169.     /* Estimate cost of deleting a line */
  170.     if (CS)        tcdell = charcost(CS)*2 + charcost(SF);
  171.     else if (pDL)    tcdell = charcost(pDL);
  172.     else if (DL)    tcdell = charcost(DL);
  173.     else        tcdell = NROW * NCOL;    /* make this cost high enough */
  174.  
  175.     /* Flag to indicate that we can both insert and delete lines */
  176.     insdel = (AL || pAL) && (DL || pDL);
  177.  
  178.     if (p >= &tcapbuf[TCAPSLEN])
  179.         panic("Terminal description too big!\n");
  180.     if (TI && *TI) putpad(TI, 1);    /* init the term */
  181. }
  182.  
  183. /*
  184.  * Clean up the terminal, in anticipation of
  185.  * a return to the command interpreter. This is a no-op
  186.  * on the ANSI display. On the SCALD display, it sets the
  187.  * window back to half screen scrolling. Perhaps it should
  188.  * query the display for the increment, and put it
  189.  * back to what it was.
  190.  */
  191. tttidy() {
  192.     if (TE && *TE) putpad(TE, 1);    /* set the term back to normal mode */
  193. #ifdef    XKEYS
  194.     ttykeymaptidy();
  195. #endif
  196. }
  197.  
  198. /*
  199.  * Move the cursor to the specified
  200.  * origin 0 row and column position. Try to
  201.  * optimize out extra moves; redisplay may
  202.  * have left the cursor in the right
  203.  * location last time!
  204.  */
  205. ttmove(row, col) {
  206.     char    *tgoto();
  207.  
  208.     if (ttrow!=row || ttcol!=col) {
  209.     putpad(tgoto(CM, col, row), 1);
  210.     ttrow = row;
  211.     ttcol = col;
  212.     }
  213. }
  214.  
  215. /*
  216.  * Erase to end of line.
  217.  */
  218. tteeol() {
  219.     if(CE) putpad(CE, 1);
  220.     else {
  221.     register int i=ncol-ttcol;
  222.     while(i--) ttputc(' ');
  223.     ttrow = ttcol = HUGE;
  224.     }
  225. }
  226.  
  227. /*
  228.  * Erase to end of page.
  229.  */
  230. tteeop() {
  231.     if(CD) putpad(CD, nrow - ttrow);
  232.     else {
  233.     putpad(CE, 1);
  234.     if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1);
  235.     else {        /* do it by hand */
  236.         register int line;
  237.         for (line = ttrow + 1; line <= LI; ++line) {
  238.         ttmove(line, 0);
  239.         tteeol();
  240.         }
  241.     }
  242.     ttrow = ttcol = HUGE;
  243.     }
  244. }
  245.  
  246. /*
  247.  * Make a noise.
  248.  */
  249. ttbeep() {
  250.     ttputc(BEL);
  251.     ttflush();
  252. }
  253.  
  254. /*
  255.  * Insert nchunk blank line(s) onto the
  256.  * screen, scrolling the last line on the
  257.  * screen off the bottom.  Use the scrolling
  258.  * region if possible for a smoother display.
  259.  * If no scrolling region, use a set
  260.  * of insert and delete line sequences
  261.  */
  262. ttinsl(row, bot, nchunk) {
  263.     register int    i, nl;
  264.  
  265.     if (row == bot) {        /* Case of one line insert is    */
  266.     ttmove(row, 0);        /*    special            */
  267.     tteeol();
  268.     return;
  269.     }
  270.     if (CS && SR) {        /* Use scroll region and back index    */
  271.     nl = bot - row;
  272.     ttwindow(row,bot);
  273.     ttmove(row, 0);
  274.     while (nchunk--) putpad(SR, nl);
  275.     ttnowindow();
  276.     return;
  277.     } else if (insdel) {
  278.     ttmove(1+bot-nchunk, 0);
  279.     nl = nrow - ttrow;
  280.     if (pDL) putpad(tgoto(pDL, 0, nchunk), nl);
  281.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  282.         putpad(DL, nl);
  283.     ttmove(row, 0);
  284.     nl = nrow - ttrow;    /* ttmove() changes ttrow */
  285.     if (pAL) putpad(tgoto(pAL, 0, nchunk), nl);
  286.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  287.         putpad(AL, nl);
  288.     ttrow = HUGE;
  289.     ttcol = HUGE;
  290.     } else panic("ttinsl: Can't insert/delete line");
  291. }
  292.  
  293. /*
  294.  * Delete nchunk line(s) from "row", replacing the
  295.  * bottom line on the screen with a blank line.
  296.  * Unless we're using the scrolling region, this is
  297.  * done with a crafty sequences of insert and delete
  298.  * lines.  The presence of the echo area makes a
  299.  * boundry condition go away.
  300.  */
  301. ttdell(row, bot, nchunk)
  302. {
  303.     register int    i, nl;
  304.  
  305.     if (row == bot) {        /* One line special case    */
  306.     ttmove(row, 0);
  307.     tteeol();
  308.     return;
  309.     }
  310.     if (CS) {            /* scrolling region    */
  311.     nl = bot - row;
  312.     ttwindow(row, bot);
  313.     ttmove(bot, 0);
  314.     while (nchunk--) putpad(SF, nl);
  315.     ttnowindow();
  316.     }
  317.     else if(insdel) {
  318.     ttmove(row, 0);            /* Else use insert/delete line    */
  319.     nl = nrow - ttrow;
  320.     if (pDL) putpad(tgoto(pDL, 0, nchunk), nl);
  321.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  322.         putpad(DL, nl);
  323.     ttmove(1+bot-nchunk,0);
  324.     nl = nrow - ttrow;    /* ttmove() changes ttrow */
  325.     if (pAL) putpad(tgoto(pAL, 0, nchunk), nl);
  326.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  327.         putpad(AL, nl);
  328.     ttrow = HUGE;
  329.     ttcol = HUGE;
  330.     } else panic("ttdell: Can't insert/delete line");
  331. }
  332.  
  333. /*
  334.  * This routine sets the scrolling window
  335.  * on the display to go from line "top" to line
  336.  * "bot" (origin 0, inclusive). The caller checks
  337.  * for the pathalogical 1 line scroll window that
  338.  * doesn't work right, and avoids it. The "ttrow"
  339.  * and "ttcol" variables are set to a crazy value
  340.  * to ensure that the next call to "ttmove" does
  341.  * not turn into a no-op (the window adjustment
  342.  * moves the cursor).
  343.  *
  344.  */
  345. ttwindow(top, bot)
  346. {
  347.     if (CS && (tttop!=top || ttbot!=bot)) {
  348.         putpad(tgoto(CS, bot, top), nrow - ttrow);
  349.         ttrow = HUGE;            /* Unknown.        */
  350.         ttcol = HUGE;
  351.         tttop = top;            /* Remember region.    */
  352.         ttbot = bot;
  353.     }
  354. }
  355.  
  356. /*
  357.  * Switch to full screen scroll. This is
  358.  * used by "spawn.c" just before is suspends the
  359.  * editor, and by "display.c" when it is getting ready
  360.  * to exit.  This function gets to full screen scroll
  361.  * by telling the terminal to set a scrolling regin
  362.  * that is LI or nrow rows high, whichever is larger.
  363.  * This behavior seems to work right on systems
  364.  * where you can set your terminal size.
  365.  */
  366. ttnowindow()
  367. {
  368.     if (CS) {
  369.     putpad(tgoto(CS, (nrow > LI ? nrow : LI) - 1, 0), nrow - ttrow);
  370.     ttrow = HUGE;            /* Unknown.        */
  371.     ttcol = HUGE;
  372.     tttop = HUGE;            /* No scroll region.    */
  373.     ttbot = HUGE;
  374.     }
  375. }
  376.  
  377. /*
  378.  * Set the current writing color to the
  379.  * specified color. Watch for color changes that are
  380.  * not going to do anything (the color is already right)
  381.  * and don't send anything to the display.
  382.  * The rainbow version does this in putline.s on a
  383.  * line by line basis, so don't bother sending
  384.  * out the color shift.
  385.  */
  386. ttcolor(color) register int color; {
  387.     if (color != tthue) {
  388.     if (color == CTEXT) {        /* Normal video.    */
  389.         putpad(SE, 1);
  390.     } else if (color == CMODE) {    /* Reverse video.    */
  391.         putpad(SO, 1);
  392.     }
  393.     tthue = color;            /* Save the color.    */
  394.     }
  395. }
  396.  
  397. /*
  398.  * This routine is called by the
  399.  * "refresh the screen" command to try and resize
  400.  * the display. The new size, which must be deadstopped
  401.  * to not exceed the NROW and NCOL limits, it stored
  402.  * back into "nrow" and "ncol". Display can always deal
  403.  * with a screen NROW by NCOL. Look in "window.c" to
  404.  * see how the caller deals with a change.
  405.  */
  406. ttresize() {
  407.     setttysize();            /* found in "ttyio.c",    */
  408.                     /* ask OS for tty size    */
  409.     if (nrow < 1)            /* Check limits.    */
  410.         nrow = 1;
  411.     else if (nrow > NROW)
  412.         nrow = NROW;
  413.     if (ncol < 1)
  414.         ncol = 1;
  415.     else if (ncol > NCOL)
  416.         ncol = NCOL;
  417. }
  418.  
  419. #ifdef NO_RESIZE
  420. static setttysize() {
  421.     nrow = tgetnum("li");
  422.     ncol = tgetnum("co");
  423. }
  424. #endif
  425.  
  426. static int cci;
  427.  
  428. /*ARGSUSED*/
  429. static int        /* fake char output for charcost() */
  430. fakec(c)
  431. char c;
  432. {
  433.     cci++;
  434. }
  435.  
  436. /* calculate the cost of doing string s */
  437. charcost (s) char *s; {
  438.     cci = 0;
  439.  
  440.     tputs(s, nrow, fakec);
  441.     return cci;
  442. }
  443.